// Copyright (c) 2024 Huawei Device Co., Ltd. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "shell/browser/api/electron_api_system_preferences.h"

#include <accesstoken/ability_access_control.h>

#include "base/logging.h"
#include "base/strings/string_util.h"
#include "base/task/thread_pool.h"
#include "filemanagement/file_uri/oh_file_uri.h"
#include "net/base/filename_util.h"
#include "ohos/adapter/dialog/dialog_adapter.h"
#include "ohos/adapter/electron_app/electron_app_adapter.h"
#include "ohos/adapter/notification/notification_adapter.h"
#include "ohos/adapter/permission_manager/permission_manager_adapter.h"
#include "shell/common/gin_helper/promise.h"

namespace electron {

using ohos::adapter::dialog::DialogAdapter;
using ohos::adapter::electron_app::ElectronAppAdapter;
using ohos::adapter::NotificationAdapter;
using ohos::adapter::permission::OHOSPermissionType;
using ohos::adapter::permission::PermissionManagerAdapter;

namespace {

constexpr char kDownloadDirPrefix[] = "/storage/Users/currentUser/Download";
constexpr char kDesktopDirPrefix[] = "/storage/Users/currentUser/Desktop";
constexpr char kDocumentDirPrefix[] = "/storage/Users/currentUser/Document";

OHOSPermissionType ConvertPermission(const std::string& permission) {
  if (permission == "location") {
    return OHOSPermissionType::LOCATION;
  } else if (permission == "camera") {
    return OHOSPermissionType::CAMERA;
  } else if (permission == "microphone") {
    return OHOSPermissionType::MICROPHONE;
  } else if (permission == "screen-capture") {
    return OHOSPermissionType::CUSTOM_SCREEN_CAPTURE;
  } else if (permission == "user-download-dir") {
    return OHOSPermissionType::USER_DOWNLOAD_DIR;
  } else if (permission == "user-desktop-dir") {
    return OHOSPermissionType::USER_DESKTOP_DIR;
  } else if (permission == "user-document-dir") {
    return OHOSPermissionType::USER_DOCUMENT_DIR;
  } else if (permission == "bluetooth") {
    return OHOSPermissionType::BLUETOOTH;
  } else if (permission == "pasteboard") {
    return OHOSPermissionType::PASTEBOARD;
  } else {
    return OHOSPermissionType::NO;
  }
}

OHOSPermissionType ConvertMediaType(const std::string& media_type) {
  if (media_type == "camera") {
    return OHOSPermissionType::CAMERA;
  } else if (media_type == "microphone") {
    return OHOSPermissionType::MICROPHONE;
  } else {
    return OHOSPermissionType::NO;
  }
}

std::string ConvertMediaTypeToString(const std::string& media_type) {
  if (media_type == "camera") {
    return "ohos.permission.CAMERA";
  } else if (media_type == "microphone") {
    return "ohos.permission.MICROPHONE";
  } else if (media_type == "screen") {
    return "ohos.permission.CUSTOM_SCREEN_CAPTURE";
  } else {
    return std::string();
  }
}

OHOSPermissionType GetPermissionTypeByFilePath(const std::string& file_path) {
  if (base::StartsWith(file_path, kDownloadDirPrefix)) {
    return OHOSPermissionType::USER_DOWNLOAD_DIR;
  } else if (base::StartsWith(file_path, kDesktopDirPrefix)) {
    return OHOSPermissionType::USER_DESKTOP_DIR;
  } else if (base::StartsWith(file_path, kDocumentDirPrefix)) {
    return OHOSPermissionType::USER_DOCUMENT_DIR;
  } else {
    return OHOSPermissionType::NO;
  }
}

bool RequestAllDirectoriesPermission() {
  return PermissionManagerAdapter::RequestPermission(
      OHOSPermissionType::USER_DOWNLOAD_DIR) &&
         PermissionManagerAdapter::RequestPermission(
             OHOSPermissionType::USER_DESKTOP_DIR) &&
         PermissionManagerAdapter::RequestPermission(
             OHOSPermissionType::USER_DOCUMENT_DIR);
}

std::vector<std::string> GetUrisFromPaths(std::vector<std::string> paths) {
  std::vector<std::string> uris;
  for (const auto& path : paths) {
    char* uri = nullptr;
    auto code = OH_FileUri_GetUriFromPath(path.c_str(), path.size(), &uri);
    if (code != FileManagement_ErrCode::ERR_OK) {
      LOG(ERROR) << "Get uri from path failed, path: " << path;
      continue;
    }
    uris.push_back(uri);
  }
  return uris;
}

}  // namespace

namespace api {

std::string SystemPreferences::GetMediaAccessStatus(
    gin_helper::ErrorThrower thrower,
    const std::string& media_type) {
  std::string permission = ConvertMediaTypeToString(media_type);
  if (permission.empty()) {
    thrower.ThrowError("Invalid media type");
    return std::string();
  }
  if (OH_AT_CheckSelfPermission(permission.c_str())) {
    return "granted";
  } else {
    return "denied";
  }
}

v8::Local<v8::Promise> SystemPreferences::AskForMediaAccess(
    v8::Isolate* isolate,
    const std::string& media_type) {
  gin_helper::Promise<bool> promise(isolate);
  v8::Local<v8::Promise> handle = promise.GetHandle();

  OHOSPermissionType ohos_permission = ConvertMediaType(media_type);
  if (ohos_permission == OHOSPermissionType::NO) {
    gin_helper::ErrorThrower thrower(isolate);
    thrower.ThrowError("Invalid media type");
  }
  base::ThreadPool::PostTaskAndReplyWithResult(
      FROM_HERE, {base::TaskPriority::USER_BLOCKING},
      base::BindOnce(&PermissionManagerAdapter::RequestPermission,
                     ohos_permission),
      base::BindOnce([](gin_helper::Promise<bool> promise,
                        bool result) { promise.Resolve(result); },
                     std::move(promise)));
  return handle;
}

v8::Local<v8::Promise> SystemPreferences::RequestSystemPermission(
    v8::Isolate* isolate,
    const std::string& permission) {
  gin_helper::Promise<bool> promise(isolate);
  v8::Local<v8::Promise> handle = promise.GetHandle();

  OHOSPermissionType ohos_permission = ConvertPermission(permission);
  if (ohos_permission == OHOSPermissionType::NO) {
    gin_helper::ErrorThrower thrower(isolate);
    thrower.ThrowError("Invalid permission name");
  }
  base::ThreadPool::PostTaskAndReplyWithResult(
      FROM_HERE, {base::TaskPriority::USER_BLOCKING},
      base::BindOnce(&PermissionManagerAdapter::RequestPermission,
                     ohos_permission),
      base::BindOnce([](gin_helper::Promise<bool> promise,
                        bool result) { promise.Resolve(result); },
                     std::move(promise)));
  return handle;
}

v8::Local<v8::Promise> SystemPreferences::RequestDirectoryPermission(
    v8::Isolate* isolate,
    gin::Arguments* args) {
  std::string path;
  args->GetNext(&path);

  gin_helper::ErrorThrower thrower(isolate);
  gin_helper::Promise<bool> promise(isolate);
  v8::Local<v8::Promise> handle = promise.GetHandle();

  if (args->Length() == 0) {
    base::ThreadPool::PostTaskAndReplyWithResult(
        FROM_HERE, {base::TaskPriority::USER_BLOCKING},
        base::BindOnce(&RequestAllDirectoriesPermission),
        base::BindOnce([](gin_helper::Promise<bool> promise,
                          bool result) { promise.Resolve(result); },
                      std::move(promise)));
    return handle;
  }

  OHOSPermissionType ohos_permission = GetPermissionTypeByFilePath(path);
  if (ohos_permission == OHOSPermissionType::NO) {
    thrower.ThrowError(
        "Invalid path. The path must start with "
        "\'/storage/Users/currentUser/Download\' or "
        "\'/storage/Users/currentUser/Desktop\' or "
        "\'/storage/Users/currentUser/Document\'");
  }
  base::ThreadPool::PostTaskAndReplyWithResult(
      FROM_HERE, {base::TaskPriority::USER_BLOCKING},
      base::BindOnce(&PermissionManagerAdapter::RequestPermission,
                     ohos_permission),
      base::BindOnce([](gin_helper::Promise<bool> promise,
                        bool result) { promise.Resolve(result); },
                     std::move(promise)));
  return handle;
}

void SystemPreferences::OpenApplicationInfoEntry() {
  ElectronAppAdapter::GetInstance().OpenApplicationInfoEntry();
}

void SystemPreferences::FileAccessPersist(
    const std::vector<std::string>& file_paths) {
  DialogAdapter::GetInstance().FileAccessPersist(GetUrisFromPaths(file_paths));
}

void SystemPreferences::ActivateFileAccessPersist(
    const std::vector<std::string>& file_paths) {
  DialogAdapter::GetInstance().ActivateFileAccessPersist(
      GetUrisFromPaths(file_paths));
}

std::vector<bool> SystemPreferences::CheckPermission(
    const std::vector<std::string>& file_paths) {
  return DialogAdapter::GetInstance().CheckPermission(
      GetUrisFromPaths(file_paths));
}

void SystemPreferences::RequestNotificationPermission() {
  NotificationAdapter::GetInstance().RequestNotificationPermission();
}

v8::Local<v8::Promise> SystemPreferences::CheckNotificationEnabled(
    v8::Isolate* isolate) {
  gin_helper::Promise<bool> promise(isolate);
  v8::Local<v8::Promise> handle = promise.GetHandle();

  base::ThreadPool::PostTaskAndReplyWithResult(
      FROM_HERE, {base::TaskPriority::USER_BLOCKING},
      base::BindOnce(&NotificationAdapter::CheckNotificationEnabled),
      base::BindOnce([](gin_helper::Promise<bool> promise,
                        bool result) { promise.Resolve(result); },
                    std::move(promise)));
  return handle;
}

}  // namespace api

}  // namespace electron
